#ifndef _DANIEL_KERR_GLMOVE_H
#define _DANIEL_KERR_GLMOVE_H

#include "driver.h"
#include "universe.h"

#define P_VIEW_OFF_X	0.0
#define P_VIEW_OFF_Y	0.4
#define P_VIEW_OFF_Z	0.0

#define TIMETOTURN		2.0

/*------------------------------------------------------------------*/

class move_C
{
	public:
		move_C(GLfloat x=0.0,GLfloat y=0.0,GLfloat z=0.0);

		void init(universe_C &god,int index,int fps,bool planettype=true);

		bool update(universe_C &god,int fps);

		// Game Motion
		void gotoPlanet(universe_C &god,int index);
		void turntoPlanet(universe_C &god,int index,int fps);
		void movetoPlanet(universe_C &god,int index,int fps,bool back);

		void lookLeft(universe_C &god,int fps);
		void lookRight(universe_C &god,int fps);

		// Accesors and Checkers
		int At()				{return AtIndex;}
		int LookAt()			{return LookAtIndex;}
		int JustAt()			{return JustAtIndex;}
		bool moving()			{return (mcount!=0);}
		int moveValue()			{return mcount;}
		void checkRots();

		// Text
		vector <string> TR_Text()	{return tr_text;}
		vector <string> OPT_Text()	{return opt_text;}
		void updateTR_Text(universe_C &god);
		void updateOPT_Text(universe_C &god);

	private:
		int AtIndex,LookAtIndex,JustAtIndex,SwitchIndex;
 		int acount,mcount,tcount,tbcount;

		bool ptype,pmoveback;

		GLfloat posx,posy,posz;
		GLfloat atx,aty,atz;
		GLfloat roty,upOff;

		GLfloat AmoveOnR_Value,AmoveUD_Value;
		GLfloat AturnTP_Value,AturnTPud_Value;

		vector <string> tr_text;
		vector <string> opt_text;

		void updateAt();
};

/*------------------------------------------------------------------*/

move_C::move_C(GLfloat x,GLfloat y,GLfloat z)
{
	AtIndex=JustAtIndex=LookAtIndex=0;
	tcount=mcount=acount=tbcount=0;

	posx=x;	posy=y; posz=z;
	roty=0; upOff=0;
	updateAt();
}

void move_C::init(universe_C &god,int index,int fps,bool planettype)
{
	ptype=planettype;

	gotoPlanet(god,index);
	lookLeft(god,fps);

	updateTR_Text(god);
	updateOPT_Text(god);
}

bool move_C::update(universe_C &god,int fps)
{
	bool rtrn=false;

	// Auto Moves
	if((AturnTP_Value!=0)&&(tcount!=0))
	{
		roty+=AturnTP_Value;
		upOff+=AturnTPud_Value;
		checkRots();
		if(--tcount==0){AturnTP_Value=AturnTPud_Value=0;}
	}

	if((AmoveOnR_Value!=0)&&(mcount!=0)&&(tcount==0))
	{
		posx+=AmoveOnR_Value*sin(roty);
		posy+=AmoveUD_Value;
		posz+=AmoveOnR_Value*cos(roty);
		if(--mcount==0){AmoveOnR_Value=AmoveUD_Value=0;}
		if(mcount%fps==0)
		{
			rtrn=true;
			if((mcount==0)&&ptype)
			{
				JustAtIndex = AtIndex;
				AtIndex = LookAtIndex;
				LookAtIndex = JustAtIndex;
				gotoPlanet(god,AtIndex);
				turntoPlanet(god,LookAtIndex,fps);
				tbcount=0;
			}
		}
	}

	if((acount!=0)&&(tcount==0))
	{
		if(--acount==0)
		{
			JustAtIndex=LookAtIndex=AtIndex;
			AtIndex=SwitchIndex;
			updateTR_Text(god);
		}
	}

	if((mcount==0)&&(tcount==0)&&(tbcount!=0))
	{turntoPlanet(god,LookAtIndex,fps);	tbcount=0;}

	updateAt();

	glMatrixMode(GL_MODELVIEW);		glLoadIdentity();
	gluLookAt(posx,posy,posz , atx,aty,atz , 0,1,0);

	return rtrn;
}

// Game Motion
void move_C::gotoPlanet(universe_C &god,int index)
{
	if(index<god.NOP())
	{
		AtIndex = JustAtIndex = index;
		posx = god.px(AtIndex) + P_VIEW_OFF_X;
		posy = god.py(AtIndex) + P_VIEW_OFF_Y;
		posz = god.pz(AtIndex) + P_VIEW_OFF_Z;
		roty = PI+(AtIndex*god.ua());
		upOff = 0;
		updateAt();
	}
	else
	{cout<<"Index doesn't exist..."<<endl;}
}

void move_C::turntoPlanet(universe_C &god,int index,int fps)
{
	if(index<god.NOP())
	{
		if(index!=AtIndex)
		{
			int i;
			if(index>AtIndex)	{i=index-AtIndex;}
			else				{i=god.NOP()-(AtIndex-index);}
			
			GLfloat goDeg = ((PI/2.0)+(AtIndex*god.ua()))+(i*(PI/god.NOP()));
			GLfloat right=goDeg-roty;
			GLfloat left=PI+PI+roty-goDeg;
		
			GLfloat err = 0.001;

			if(((right>err)||(right<-err))&&((left>err)||(left<-err)))
			{
				tcount = TIMETOTURN*fps;
				if(right<left)	{AturnTP_Value=right/tcount;}
				else			{AturnTP_Value=-left/tcount;}
			}

			double ttx = (double)(god.px(index)-god.px(AtIndex));
			double tty = (double)(god.py(index)-god.py(AtIndex));
			double ttz = (double)(god.pz(index)-god.pz(AtIndex));
			double dst = sqrt(pow(ttx,2.0)+pow(ttz,2.0));
			AturnTPud_Value=((tty/dst)-upOff)/tcount;
		}				
	}
	else
	{cout<<"Index doesn't exist..."<<endl;}
}

void move_C::movetoPlanet(universe_C &god,int index,int fps,bool back)
{
	acount=mcount=tcount=tbcount=0;
	AmoveOnR_Value=AmoveUD_Value=0;
	AturnTP_Value=AturnTPud_Value=0;

	if(index<god.NOP())
	{
		turntoPlanet(god,index,fps);

		if(god.weight(AtIndex,index)>0)
		{
			double ttx = (double)(posx-(god.px(index)+P_VIEW_OFF_X));
			double ttz = (double)(posz-(god.pz(index)+P_VIEW_OFF_Z));
			double height = sqrt(pow(ttx,2.0)+pow(ttz,2.0));
			
			mcount=god.weight(AtIndex,index);
			if(back){if(mcount>1){--mcount;}}
			mcount*=fps;
			AmoveOnR_Value=height/mcount;

			/*
			if(god.py(AtIndex)>god.py(index))
			{AmoveUD_Value=-(god.py(AtIndex)-god.py(index))/mcount;}
			else
			{AmoveUD_Value=(god.py(index)-god.py(AtIndex))/mcount;}
			*/

			if(posy>god.py(index))
			{AmoveUD_Value=-(posy-(god.py(index)+P_VIEW_OFF_Y))/mcount;}
			else
			{AmoveUD_Value=((god.py(index)+P_VIEW_OFF_Y)-posy)/mcount;}


			SwitchIndex=index;
			acount=(mcount-fps);
			if(acount==0){acount=(mcount/2.0);}

			tbcount = 1;
		}
	}
	else
	{cout<<"Index doesn't exist..."<<endl;}
}

void move_C::lookLeft(universe_C &god,int fps)
{
	++LookAtIndex;
	if(LookAtIndex>=god.NOP())				{LookAtIndex-=god.NOP();}
	if(god.weight(AtIndex,LookAtIndex)<1)	{lookLeft(god,fps);}
	else {turntoPlanet(god,LookAtIndex,fps);}
	updateOPT_Text(god);
}

void move_C::lookRight(universe_C &god,int fps)
{
	--LookAtIndex;
	if(LookAtIndex<0)						{LookAtIndex+=god.NOP();}
	if(god.weight(AtIndex,LookAtIndex)<1)	{lookRight(god,fps);}
	else {turntoPlanet(god,LookAtIndex,fps);}
	updateOPT_Text(god);
}

void move_C::checkRots()
{
	if(roty<0)		{roty+=(2*PI);}
	if(roty>(2*PI))	{roty-=(2*PI);}
}

/*------------------------------------------------------------------*/

void move_C::updateTR_Text(universe_C &god)
{
	tr_text.clear();
	tr_text = god.ppinfo(AtIndex);
}

void move_C::updateOPT_Text(universe_C &god)
{
	char buf[3];
	
	opt_text.clear();
	_itoa_s(god.weight(AtIndex,LookAtIndex),buf,10);
	opt_text.push_back("Move ("+(string)buf+"turn)");
	opt_text.push_back("Train (1turn)");
	opt_text.push_back("Spy (1turn)");
	opt_text.push_back("Do Nothing");
}

/*------------------------------------------------------------------*/

void move_C::updateAt()
{
	atx=posx + sin(roty);
	aty=posy + upOff;
	atz=posz + cos(roty);
}

/*------------------------------------------------------------------*/

#endif